/*
 * Licensed to the Tai Ping Jin Ke
 *
 * Copyright (c) 2022 .
 * All rights reserved.
 * 项目名称：太平金科-通用能力封装层-json字符串操作
 * 版权说明：本软件属太平金融科技服务(上海)有限公司所有，在未获得太平金融科技服务(上海)有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.taipingframework.json;

import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.json.JsonWriteFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
// import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
// import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.csv.CsvFactory;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvParser;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.fasterxml.jackson.dataformat.javaprop.JavaPropsFactory;
import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;
import com.fasterxml.jackson.dataformat.javaprop.JavaPropsParser;
import com.fasterxml.jackson.dataformat.javaprop.JavaPropsSchema;
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import com.taipingframework.utility.exception.UtilityException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone;

/**
 * Jackson工具类
 * 优势：
 * 1、反序列化场景支持最完善，API最完善，注解支持最完善，可定制性最强
 * 2、支持的数据源最广泛（字符串，对象，文件、流、URL、Properties、YAML、CSV、XML），数据量大的时候，速度和Fastjson相差很小
 * 317 周孝兵 更新于 2021-11-24
 */
@Slf4j
@SuppressWarnings({"unused"})
public class JacksonHelper {
    private static ObjectMapper mapper;
    private static YAMLMapper yamlMapper;
    private static JavaPropsMapper propsMapper;
    private static CsvMapper csvMapper;
    private static XmlMapper xmlMapper;

    /**
     * 序列化级别，默认只序列化属性值发生过改变的字段
     */
    private static JsonInclude.Include defaultPropertyInclusion = JsonInclude.Include.ALWAYS;

    /**
     * 是否缩进JSON格式
     */
    private static boolean isEnableIndentOutput = false;

    /**
     * CSV默认分隔符
     */
    private static String csvDefaultColumnSeparator = ",";

    static {
        try {
            //初始化
            initMapper();
            //配置序列化级别
            configPropertyInclusion();
            //配置JSON缩进支持
            configIndentOutput();
            //配置普通属性
            configCommon();
            //配置特殊属性
            configSpecial();
        } catch (Exception e) {
            log.error("jackson config error", e);
        }
    }

    private static void initMapper() {
        // 1、json
        JsonFactory jsonFactory = JsonFactory.builder()
                //识别特殊字符
                .enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS)
                //强制转义非ascii字符
                .disable(JsonWriteFeature.ESCAPE_NON_ASCII)
                .build();
        mapper = new ObjectMapper(jsonFactory);

        // 2、yaml
        YAMLFactory yamlFactory = YAMLFactory.builder().build();
        yamlMapper = new YAMLMapper(yamlFactory);

        // 3、properties
        JavaPropsFactory propsFactory = JavaPropsFactory.builder().build();
        propsMapper = new JavaPropsMapper(propsFactory);

        // 4、csv
        CsvFactory csvFactory = CsvFactory.builder().build();
        csvMapper = new CsvMapper(csvFactory);

        // 5、xml
        XmlFactory xmlFactory = XmlFactory.builder().build();
        xmlMapper = new XmlMapper(xmlFactory);
    }

    private static void configCommon() {
        config(mapper);
        config(yamlMapper);
        config(propsMapper);
        config(csvMapper);
        config(xmlMapper);
    }

    private static void configPropertyInclusion() {
        mapper.setSerializationInclusion(defaultPropertyInclusion);
        yamlMapper.setSerializationInclusion(defaultPropertyInclusion);
        propsMapper.setSerializationInclusion(defaultPropertyInclusion);
        csvMapper.setSerializationInclusion(defaultPropertyInclusion);
        xmlMapper.setSerializationInclusion(defaultPropertyInclusion);
    }

    private static void configIndentOutput() {
        mapper.configure(SerializationFeature.INDENT_OUTPUT, isEnableIndentOutput);
        yamlMapper.configure(SerializationFeature.INDENT_OUTPUT, isEnableIndentOutput);
        propsMapper.configure(SerializationFeature.INDENT_OUTPUT, isEnableIndentOutput);
        csvMapper.configure(SerializationFeature.INDENT_OUTPUT, isEnableIndentOutput);
        xmlMapper.configure(SerializationFeature.INDENT_OUTPUT, isEnableIndentOutput);
    }

    private static void configSpecial() {
        //使用系统换行符
        yamlMapper.enable(YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS);
        //允许注释
        yamlMapper.enable(JsonParser.Feature.ALLOW_COMMENTS);
        yamlMapper.enable(JsonParser.Feature.ALLOW_YAML_COMMENTS);
        //允许注释
        propsMapper.enable(JavaPropsParser.Feature.ALLOW_COMMENTS);
        propsMapper.enable(JavaPropsParser.Feature.ALLOW_YAML_COMMENTS);
        //去掉头尾空格
        csvMapper.enable(CsvParser.Feature.TRIM_SPACES);
        //忽略空行
        csvMapper.enable(CsvParser.Feature.SKIP_EMPTY_LINES);
        csvMapper.enable(CsvParser.Feature.WRAP_AS_ARRAY);
    }

    private static void config(ObjectMapper objectMapper) {
        //序列化BigDecimal时之间输出原始数字还是科学计数, 默认false, 即是否以toPlainString()科学计数方式来输出
        objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
        //允许将JSON空字符串强制转换为null对象值
        objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

        //允许单个数值当做数组处理
        objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);

        //禁止重复键, 抛出异常
        objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
        //禁止使用int代表Enum的order()來反序列化Enum, 抛出异常
        objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
        //有属性不能映射的时候不报错
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        //使用null表示集合类型字段是时不抛异常
        objectMapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
        //对象为空时不抛异常
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

        //允许在JSON中使用c/c++风格注释
        objectMapper.enable(JsonParser.Feature.ALLOW_COMMENTS);
        //强制转义非ascii字符(@Deprecated) - 替换已过时的属性设置方式
        //objectMapper.disable(JsonGenerator.Feature.ESCAPE_NON_ASCII);
        //允许未知字段
        objectMapper.enable(JsonGenerator.Feature.IGNORE_UNKNOWN);
        //在JSON中允许未引用的字段名
        objectMapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
        //时间格式
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN));
        //识别单引号
        objectMapper.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
        //识别特殊字符(@Deprecated) - 替换已过时的属性设置方式
        //objectMapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS);

        //Java8时间对象LocalDateTime序列化与反序列化设置（自定义）
        JavaTimeModule module = new JavaTimeModule();
        //日期时间
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter));
        // module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter));
        //日期
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN);
        module.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter));
        module.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter));
        //时间
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN);
        module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter));
        module.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter));
        //注册
        objectMapper.registerModule(module);

        //识别Java8时间
        objectMapper.registerModule(new ParameterNamesModule());
        objectMapper.registerModule(new Jdk8Module());
        //识别Guava包的类
        objectMapper.registerModule(new GuavaModule());
    }

    /**
     * 设置序列化级别
     * NON_NULL：序列化非空的字段
     * NON_EMPTY：序列化非空字符串和非空的字段
     * NON_DEFAULT：序列化属性值发生过改变的字段
     */
    public static void setSerializationInclusion(JsonInclude.Include inclusion) {
        JacksonHelper.defaultPropertyInclusion = inclusion;
        configPropertyInclusion();
    }

    /**
     * 设置是否开启JSON格式美化
     *
     * @param isEnable 为true表示开启, 默认false, 有些场合为了便于排版阅读则需要对输出做缩放排列
     */
    public static void setIndentOutput(boolean isEnable) {
        JacksonHelper.isEnableIndentOutput = isEnable;
        configIndentOutput();
    }

    public static ObjectMapper getObjectMapper() {
        return mapper;
    }

    /**
     * 配置 redis-template 需要的 ObjectMapper
     */
    public static ObjectMapper getObjectMapperForRedis() {
        // 目前已知的是，redis-template会额外需要下面这几项配置
        ObjectMapper mapperCopy = mapper.copy();
        mapperCopy.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapperCopy.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        mapperCopy.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN));
        mapperCopy.setTimeZone(TimeZone.getDefault());
        mapperCopy.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        mapperCopy.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapperCopy;
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(URL url, Class<V> c) throws UtilityException {
        try {
            return mapper.readValue(url, c);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(InputStream inputStream, Class<V> c) throws UtilityException {
        try {
            return mapper.readValue(inputStream, c);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(File file, Class<V> c) throws UtilityException {
        try {
            return mapper.readValue(file, c);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(Object jsonObj, Class<V> c) throws UtilityException {
        try {
            return mapper.readValue(jsonObj.toString(), c);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(String json, Class<V> c) throws UtilityException {
        try {
            return mapper.readValue(json, c);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(URL url, TypeReference<V> type) throws UtilityException {
        try {
            return mapper.readValue(url, type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(InputStream inputStream, TypeReference<V> type) throws UtilityException {
        try {
            return mapper.readValue(inputStream, type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(File file, TypeReference<V> type) throws UtilityException {
        try {
            return mapper.readValue(file, type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(Object jsonObj, TypeReference<V> type) throws UtilityException {
        try {
            return mapper.readValue(jsonObj.toString(), type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * JSON反序列化
     */
    public static <V> V from(String json, TypeReference<V> type) throws UtilityException {
        try {
            return mapper.readValue(json, type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Resources目录下的Yaml文件
     *
     * @param name 文件名
     */
    public static <V> V fromYamlResource(String name, Class<V> clazz) throws UtilityException {
        try (InputStream inputStream = getResourceStream(name)) {
            try (InputStreamReader reader = getResourceReader(inputStream)) {
                return yamlMapper.readValue(reader, clazz);
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Resources目录下的Yaml文件
     *
     * @param name 文件名
     */
    public static <V> V fromYamlResource(String name, TypeReference<V> type) throws UtilityException {
        try (InputStream inputStream = getResourceStream(name)) {
            try (InputStreamReader reader = getResourceReader(inputStream)) {
                return yamlMapper.readValue(reader, type);
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Yaml文件
     *
     * @param path 文件路径
     */
    public static <V> V fromYamlFile(String path, Class<V> c) throws UtilityException {
        try {
            return yamlMapper.readValue(new File(path), c);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Yaml文件
     *
     * @param path 文件路径
     */
    public static <V> V fromYamlFile(String path, TypeReference<V> type) throws UtilityException {
        try {
            return yamlMapper.readValue(new File(path), type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Resources目录下的Properties文件
     *
     * @param name 文件名
     */
    public static <V> V fromPropResource(String name, Class<V> clazz) throws UtilityException {
        try (InputStream inputStream = getResourceStream(name); InputStreamReader reader = getResourceReader(inputStream)) {
            return propsMapper.readValue(reader, clazz);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Resources目录下的Properties文件
     *
     * @param name 文件名
     */
    public static <V> V fromPropResource(String name, TypeReference<V> type) throws UtilityException {
        try (InputStream inputStream = getResourceStream(name); InputStreamReader reader = getResourceReader(inputStream)) {
            return propsMapper.readValue(reader, type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Resources目录下的Csv文件（受限于CSV的格式，Jackson不支持深层次结构的CSV反序列化，不支持嵌套类）
     *
     * @param name 文件名
     */
    public static <V> List<V> fromCsvResource(String name, Class<V> c) throws UtilityException {
        return fromCsvResource(name, csvDefaultColumnSeparator, c);
    }

    /**
     * 反序列化Resources目录下的Csv文件（受限于CSV的格式，Jackson不支持深层次结构的CSV反序列化，不支持嵌套类）
     *
     * @param name      文件名
     * @param separator cloumn的分隔符
     */
    @SuppressWarnings("unchecked")
    public static <V> List<V> fromCsvResource(String name, String separator, Class<V> c) throws UtilityException {
        try (InputStream inputStream = getResourceStream(name); InputStreamReader reader = getResourceReader(inputStream)) {
            CsvSchema schema = CsvSchema.builder().setColumnSeparator(separator.charAt(0)).setUseHeader(true).build();
            return (List<V>) csvMapper.reader(schema).forType(c).readValues(reader).readAll();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Csv文件（受限于CSV的格式，Jackson不支持深层次结构的CSV反序列化，不支持嵌套类）
     *
     * @param path 文件路径
     */
    public static <V> List<V> fromCsvFile(String path, Class<V> c) throws UtilityException {
        return fromCsvFile(path, csvDefaultColumnSeparator, c);
    }

    /**
     * 反序列化Csv文件（受限于CSV的格式，Jackson不支持深层次结构的CSV反序列化，不支持嵌套类）
     *
     * @param separator cloumn的分隔符
     * @param path      文件路径
     */
    @SuppressWarnings("unchecked")
    public static <V> List<V> fromCsvFile(String path, String separator, Class<V> c) throws UtilityException {
        try {
            CsvSchema schema = CsvSchema.builder().setColumnSeparator(separator.charAt(0)).setUseHeader(true).build();
            return (List<V>) csvMapper.reader(schema).forType(c).readValues(new File(path)).readAll();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Resources目录下的Xml文件
     *
     * @param name 文件名
     */
    public static <V> V fromXmlResource(String name, Class<V> clazz) throws UtilityException {
        try (InputStream inputStream = getResourceStream(name); InputStreamReader reader = getResourceReader(inputStream)) {
            return xmlMapper.readValue(reader, clazz);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Resources目录下的Xml文件
     *
     * @param name 文件名
     */
    public static <V> V fromXmlResource(String name, TypeReference<V> type) throws UtilityException {
        try (InputStream inputStream = getResourceStream(name); InputStreamReader reader = getResourceReader(inputStream)) {
            return xmlMapper.readValue(reader, type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Xml文件
     *
     * @param path 文件路径
     */
    public static <V> V fromXmlFile(String path, Class<V> c) throws UtilityException {
        try {
            return xmlMapper.readValue(new File(path), c);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Xml文件
     *
     * @param path 文件路径
     */
    public static <V> V fromXmlFile(String path, TypeReference<V> type) throws UtilityException {
        try {
            return xmlMapper.readValue(new File(path), type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Xml字符串
     */
    public static <V> V fromXml(String xml, Class<V> c) throws UtilityException {
        try {
            return xmlMapper.readValue(xml, c);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 反序列化Xml字符串
     */
    public static <V> V fromXml(String xml, TypeReference<V> type) throws UtilityException {
        try {
            return xmlMapper.readValue(xml, type);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为JSON
     */
    public static <V> String to(List<V> list) throws UtilityException {
        try {
            return mapper.writeValueAsString(list);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为JSON
     */
    public static <V> String to(V v) throws UtilityException {
        try {
            return mapper.writeValueAsString(v);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为JSON
     */
    public static <V> void toFile(String path, List<V> list) throws UtilityException {
        try (Writer writer = new OutputStreamWriter(new FileOutputStream(new File(path), true), StandardCharsets.UTF_8.name())) {
            mapper.writer().writeValues(writer).writeAll(list);
            writer.flush();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为JSON
     */
    public static <V> void toFile(String path, V v) throws UtilityException {
        try (Writer writer = new OutputStreamWriter(new FileOutputStream(new File(path), true), StandardCharsets.UTF_8.name())) {
            mapper.writer().writeValues(writer).write(v);
            writer.flush();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为YAML
     */
    public static <V> String toYaml(V v) throws UtilityException {
        try {
            return yamlMapper.writeValueAsString(v);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为YAML文件
     */
    public static <V> void toYamlFile(String path, V v) throws UtilityException {
        try (Writer writer = new OutputStreamWriter(new FileOutputStream(new File(path), true), StandardCharsets.UTF_8.name())) {
            yamlMapper.writeValue(writer, v);
            writer.flush();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为Properties
     */
    public static <V> String toProp(V v) throws UtilityException {
        try {
            String string = propsMapper.writeValueAsString(v);
            return new String(string.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为Properties文件
     */
    public static <V> void toPropFile(String path, V v) throws UtilityException {
        try (Writer writer = new OutputStreamWriter(new FileOutputStream(new File(path), true), StandardCharsets.UTF_8.name())) {
            JavaPropsSchema schema = JavaPropsSchema.emptySchema();
            propsMapper.writer(schema).writeValues(writer).write(v);
            writer.flush();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为CSV
     */
    public static <V> String toCsv(List<V> list) throws UtilityException {
        return toCsv(csvDefaultColumnSeparator, list);
    }

    /**
     * 序列化为CSV
     */
    public static <V> String toCsv(String separator, List<V> list) throws UtilityException {
        try {
            Class<?> type = list.get(0).getClass();
            CsvSchema schema = csvMapper.schemaFor(type).withHeader().withColumnSeparator(separator.charAt(0));
            return csvMapper.writer(schema).writeValueAsString(list);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为CSV
     */
    public static <V> String toCsv(V v) throws UtilityException {
        return toCsv(csvDefaultColumnSeparator, v);
    }

    /**
     * 序列化为CSV
     */
    public static <V> String toCsv(String separator, V v) throws UtilityException {
        try {
            CsvSchema schema = csvMapper.schemaFor(v.getClass()).withHeader().withColumnSeparator(separator.charAt(0));
            return csvMapper.writer(schema).writeValueAsString(v);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为CSV文件
     */
    public static <V> void toCsvFile(String path, List<V> list) throws UtilityException {
        toCsvFile(path, csvDefaultColumnSeparator, list);
    }

    /**
     * 序列化为CSV文件
     */
    public static <V> void toCsvFile(String path, String separator, List<V> list) throws UtilityException {
        try (Writer writer = new OutputStreamWriter(new FileOutputStream(new File(path), true), StandardCharsets.UTF_8.name())) {
            Class<?> type = list.get(0).getClass();
            CsvSchema schema = csvMapper.schemaFor(type).withHeader().withColumnSeparator(separator.charAt(0));
            csvMapper.writer(schema).writeValues(writer).writeAll(list);
            writer.flush();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为CSV文件
     */
    public static <V> void toCsvFile(String path, V v) throws UtilityException {
        toCsvFile(path, csvDefaultColumnSeparator, v);
    }

    /**
     * 序列化为CSV文件
     */
    public static <V> void toCsvFile(String path, String separator, V v) throws UtilityException {
        try (Writer writer = new OutputStreamWriter(new FileOutputStream(new File(path), true), StandardCharsets.UTF_8.name())) {
            CsvSchema schema = csvMapper.schemaFor(v.getClass()).withHeader().withColumnSeparator(separator.charAt(0));
            csvMapper.writer(schema).writeValues(writer).write(v);
            writer.flush();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为XML
     */
    public static <V> String toXml(V v) throws UtilityException {
        return toXml(v, true);
    }

    /**
     * 序列化为XML
     */
    public static <V> String toXml(V v, boolean isIndent) throws UtilityException {
        try {
            if (isIndent) {
                return xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(v);
            } else {
                return xmlMapper.writeValueAsString(v);
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 序列化为XML文件
     */
    public static <V> void toXmlFile(String path, V v) throws UtilityException {
        toXmlFile(path, v, true);
    }

    /**
     * 序列化为XML文件
     */
    public static <V> void toXmlFile(String path, V v, boolean isIndent) throws UtilityException {
        try (Writer writer = new OutputStreamWriter(new FileOutputStream(new File(path), true), StandardCharsets.UTF_8.name())) {
            if (isIndent) {
                xmlMapper.writerWithDefaultPrettyPrinter().writeValue(writer, v);
            } else {
                xmlMapper.writeValue(writer, v);
            }
            writer.flush();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 从json串中获取某个字段
     *
     * @return String
     */
    public static String getString(String json, String key) throws UtilityException {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            JsonNode node = mapper.readTree(json);
            if (null != node) {
                return node.get(key).toString();
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
        return null;
    }

    /**
     * 从json串中获取某个字段
     *
     * @return int
     */
    public static Integer getInt(String json, String key) throws UtilityException {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            JsonNode node = mapper.readTree(json);
            if (null != node) {
                return node.get(key).intValue();
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
        return null;
    }

    /**
     * 从json串中获取某个字段
     *
     * @return long
     */
    public static Long getLong(String json, String key) throws UtilityException {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            JsonNode node = mapper.readTree(json);
            if (null != node) {
                return node.get(key).longValue();
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
        return null;
    }

    /**
     * 从json串中获取某个字段
     *
     * @return double
     */
    public static Double getDouble(String json, String key) throws UtilityException {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            JsonNode node = mapper.readTree(json);
            if (null != node) {
                return node.get(key).doubleValue();
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
        return null;
    }

    /**
     * 从json串中获取某个字段
     *
     * @return double
     */
    public static BigInteger getBigInteger(String json, String key) throws UtilityException {
        if (StringUtils.isEmpty(json)) {
            return new BigInteger(String.valueOf(0.00));
        }
        try {
            JsonNode node = mapper.readTree(json);
            if (null != node) {
                return node.get(key).bigIntegerValue();
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
        return null;
    }

    /**
     * 从json串中获取某个字段
     *
     * @return double
     */
    public static BigDecimal getBigDecimal(String json, String key) throws UtilityException {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            JsonNode node = mapper.readTree(json);
            if (null != node) {
                return node.get(key).decimalValue();
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
        return null;
    }

    /**
     * 从json串中获取某个字段
     *
     * @return boolean, 默认为false
     */
    public static boolean getBoolean(String json, String key) throws UtilityException {
        if (StringUtils.isEmpty(json)) {
            return false;
        }
        try {
            JsonNode node = mapper.readTree(json);
            if (null != node) {
                return node.get(key).booleanValue();
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
        return false;
    }

    /**
     * 从json串中获取某个字段
     *
     * @return boolean, 默认为false
     */
    public static byte[] getByte(String json, String key) throws UtilityException {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            JsonNode node = mapper.readTree(json);
            if (null != node) {
                return node.get(key).binaryValue();
            }
        } catch (Exception e) {
            throw new UtilityException(e);
        }
        return null;
    }

    /**
     * 从json串中获取某个字段
     *
     * @return boolean, 默认为false
     */
    public static <T> ArrayList<T> getList(String json, String key) throws UtilityException {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        String string = getString(json, key);
        return from(string, new TypeReference<ArrayList<T>>() {
        });
    }

    /**
     * 向json中添加属性
     *
     * @return json
     */
    public static <T> String add(String json, String key, T value) throws UtilityException {
        try {
            JsonNode node = mapper.readTree(json);
            add(node, key, value);
            return node.toString();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 向json中添加属性
     */
    private static <T> void add(JsonNode jsonNode, String key, T value) throws UtilityException {
        if (value instanceof String) {
            ((ObjectNode) jsonNode).put(key, (String) value);
        } else if (value instanceof Short) {
            ((ObjectNode) jsonNode).put(key, (Short) value);
        } else if (value instanceof Integer) {
            ((ObjectNode) jsonNode).put(key, (Integer) value);
        } else if (value instanceof Long) {
            ((ObjectNode) jsonNode).put(key, (Long) value);
        } else if (value instanceof Float) {
            ((ObjectNode) jsonNode).put(key, (Float) value);
        } else if (value instanceof Double) {
            ((ObjectNode) jsonNode).put(key, (Double) value);
        } else if (value instanceof BigDecimal) {
            ((ObjectNode) jsonNode).put(key, (BigDecimal) value);
        } else if (value instanceof BigInteger) {
            ((ObjectNode) jsonNode).put(key, (BigInteger) value);
        } else if (value instanceof Boolean) {
            ((ObjectNode) jsonNode).put(key, (Boolean) value);
        } else if (value instanceof byte[]) {
            ((ObjectNode) jsonNode).put(key, (byte[]) value);
        } else {
            ((ObjectNode) jsonNode).put(key, to(value));
        }
    }

    /**
     * 除去json中的某个属性
     *
     * @return json
     */
    public static String remove(String json, String key) throws UtilityException {
        try {
            JsonNode node = mapper.readTree(json);
            ((ObjectNode) node).remove(key);
            return node.toString();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 修改json中的属性
     */
    public static <T> String update(String json, String key, T value) throws UtilityException {
        try {
            JsonNode node = mapper.readTree(json);
            ((ObjectNode) node).remove(key);
            add(node, key, value);
            return node.toString();
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 格式化Json(美化)
     *
     * @return json
     */
    public static String format(String json) {
        try {
            JsonNode node = mapper.readTree(json);
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
        } catch (Exception ignored) {
            return json;
        }
    }

    /**
     * 判断字符串是否是json
     *
     * @return json
     */
    public static boolean isJson(String json) {
        try {
            mapper.readTree(json);
            return true;
        } catch (Exception ignored) {
            return false;
        }
    }

    /**
     * 通过Jackson的TypeFactory动态构建反序列化的类型（类似于TypeReference<T>），将json字符串动态转换为声明目标对象的引用类型
     *
     * @param value           JSON字符串
     * @param exactReturnType 在运行时经过动态反射之后得到未知引用类型
     * @return 通过反序列化得到未知引用类型的目标对象并作为Object类型返回(装箱)
     * @throws UtilityException 运行时抛出UtilityException异常
     */
    public static Object stringValueCastToTargetType(String value, Type exactReturnType) throws UtilityException {
        try {
            // 判断方法的返回类型是否为泛型
            if (exactReturnType instanceof ParameterizedType) {
                // 通过Jackson的TypeFactory动态构建反序列化的类型（类似于TypeReference<T>）
                Class<?> rawClass = mapper.getTypeFactory()
                        .constructType(((ParameterizedType) exactReturnType).getRawType())
                        .getRawClass();
                Class<?>[] classes = Arrays.stream(((ParameterizedType) exactReturnType).getActualTypeArguments())
                        .map(type -> mapper.getTypeFactory().constructType(type).getRawClass())
                        .toArray(Class[]::new);
                JavaType javaType = mapper.getTypeFactory().constructParametricType(rawClass, classes);
                return mapper.readValue(value, javaType);
            }
            // 方法的返回类型是JavaType
            Class<?> rawClass = mapper.getTypeFactory().constructType(exactReturnType).getRawClass();
            return mapper.readValue(value, rawClass);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 加载资源
     *
     * @param name 资源全路径名(classpath)
     * @return 返回字节流
     */
    private static InputStream getResourceStream(String name) {
        if (StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("'name' must not be empty or whitespace");
        }
        return JacksonHelper.class.getClassLoader().getResourceAsStream(name);
    }

    /**
     * 将字节流转换为字符流
     *
     * @param inputStream 字节流
     * @return 返回字符流
     */
    private static InputStreamReader getResourceReader(InputStream inputStream) {
        if (null == inputStream) {
            throw new IllegalArgumentException("'inputStream' must not be null");
        }
        return new InputStreamReader(inputStream, StandardCharsets.UTF_8);
    }

    /*
     * 序列化
     *
    static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            if (value != null) {
                long timestamp = value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                gen.writeNumber(timestamp);
            }
        }
    }*/

    static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
        private DateTimeFormatter dateTimeFormatter;

        LocalDateTimeDeserializer(DateTimeFormatter dateTimeFormatter) {
            this.dateTimeFormatter = dateTimeFormatter;
        }

        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            JsonToken currentToken = p.getCurrentToken();
            int id = currentToken.id();
            if (id == JsonToken.VALUE_STRING.id()) {
                String dateStr = p.getValueAsString();
                return LocalDateTime.parse(dateStr, dateTimeFormatter);
            } else {
                long timestamp = p.getValueAsLong(0L);
                if (timestamp > 0) {
                    return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
                }
                return null;
            }
        }
    }

}
